package cn.jlearn.proxy.server.handler;

import cn.hutool.core.date.DatePattern;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.StrUtil;
import cn.jlearn.proxy.common.body.TcpBody;
import cn.jlearn.proxy.common.enums.MsgTypeEnum;
import cn.jlearn.proxy.common.enums.ProtocolEnum;
import cn.jlearn.proxy.common.packet.BsPacket;
import cn.jlearn.proxy.common.packet.TcpPacket;
import cn.jlearn.proxy.server.container.ProxyServer;
import cn.jlearn.proxy.server.utils.RedissonUtil;
import com.alibaba.fastjson.JSON;
import org.tio.core.ChannelContext;
import org.tio.core.Tio;
import org.tio.core.TioConfig;
import org.tio.core.exception.TioDecodeException;
import org.tio.core.intf.Packet;
import org.tio.server.intf.ServerAioHandler;

import java.nio.ByteBuffer;
import java.nio.charset.StandardCharsets;
import java.util.Date;
import java.util.StringTokenizer;

/**
 * @author qianyingchao
 * @version 1.0
 * @date 2021/5/10 4:13 下午
 */
public class ForwardServerHandler implements ServerAioHandler {

    @Override
    public Packet decode(ByteBuffer buffer, int limit, int position, int readableLength, ChannelContext channelContext) throws TioDecodeException {
        TcpPacket tcpPacket = new TcpPacket();
        byte[] dst = new byte[readableLength];
        buffer.get(dst);
        tcpPacket.setBody(dst);

        String host = null;
        String head = new String(tcpPacket.getBody());
        StringTokenizer st = new StringTokenizer(head, "\r\n");
        while (st.hasMoreTokens()) {
            String line = st.nextToken();
            if (line.contains("Host")) {
                host = StrUtil.trim(line.split(":")[1]);
                break;
            }
        }
        if (StrUtil.isBlank(host)) {
            tcpPacket.setBody(null);
            return tcpPacket;
        }
        String token = RedissonUtil.getInstance().get(host);
        if (StrUtil.isBlank(token)) {
            tcpPacket.setBody(null);
            return tcpPacket;
        }

        channelContext.set("token", token);

        return tcpPacket;
    }

    @Override
    public ByteBuffer encode(Packet packet, TioConfig tioConfig, ChannelContext channelContext) {
        TcpPacket tcpPacket = (TcpPacket) packet;
        byte[] body = tcpPacket.getBody();
        ByteBuffer buffer = ByteBuffer.allocate(body.length);
        buffer.order(tioConfig.getByteOrder());
        buffer.put(body);
        return buffer;
    }

    @Override
    public void handler(Packet packet, ChannelContext channelContext) throws Exception {
        TcpPacket tcpPacket = (TcpPacket) packet;
        String token = (String) channelContext.get("token");

        if (tcpPacket.getBody() == null) {
            TcpPacket notFoundTcpBody = new TcpPacket();
            StringBuilder sb = new StringBuilder();
            sb.append("HTTP/1.1 404").append("\r\n");
            sb.append("Content-Type: text/html;charset=utf-8").append("\r\n");
            sb.append("Content-Language: en").append("\r\n");
            sb.append("Content-Length: 431").append("\r\n");
            sb.append("Date: ").append(DateUtil.format(new Date(), DatePattern.HTTP_DATETIME_FORMAT)).append("\r\n");
            sb.append("Keep-Alive: timeout=60").append("\r\n");
            sb.append("Connection: keep-alive").append("\r\n");
            sb.append("\r\n");
            sb.append("<!doctype html><html lang=\"en\"><head><title>HTTP Status 404 – Not Found</title><style type=\"text/css\">body {font-family:Tahoma,Arial,sans-serif;} h1, h2, h3, b {color:white;background-color:#525D76;} h1 {font-size:22px;} h2 {font-size:16px;} h3 {font-size:14px;} p {font-size:12px;} a {color:black;} .line {height:1px;background-color:#525D76;border:none;}</style></head><body><h1>HTTP Status 404 – Not Found</h1></body></html>").append("\r\n");
            notFoundTcpBody.setBody(sb.toString().getBytes(StandardCharsets.UTF_8));

            Tio.send(channelContext, notFoundTcpBody);
        }

        TcpBody tcpBody = new TcpBody(tcpPacket.getBody(), channelContext.getId(), ProtocolEnum.HTTP.getCode());
        BsPacket bsPacket = new BsPacket(MsgTypeEnum.TCP_FORWARD_REQ.getCode(), JSON.toJSONBytes(tcpBody));
        Tio.sendToBsId(ProxyServer.serverTioConfig, token, bsPacket);
    }

}
